home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / hiscore.c < prev    next >
C/C++ Source or Header  |  2000-04-25  |  8KB  |  359 lines

  1. /*    hiscore.c
  2. **    generalized high score save/restore support
  3. */
  4.  
  5. #include "driver.h"
  6. #include "hiscore.h"
  7.  
  8. #define MAX_CONFIG_LINE_SIZE 48
  9.  
  10. #define VERBOSE 0
  11.  
  12. #if VERBOSE
  13. #define LOG(x)    logerror x
  14. #else
  15. #define LOG(x)
  16. #endif
  17.  
  18. char *db_filename = "hiscore.dat"; /* high score definition file */
  19.  
  20. static struct
  21. {
  22.     int hiscores_have_been_loaded;
  23.  
  24.     struct mem_range
  25.     {
  26.         UINT32 cpu, addr, num_bytes, start_value, end_value;
  27.         struct mem_range *next;
  28.     } *mem_range;
  29. } state;
  30.  
  31. /*****************************************************************************/
  32.  
  33. #define MEMORY_READ(index,offset) \
  34.     ((*cpuintf[Machine->drv->cpu[index].cpu_type & ~CPU_FLAGS_MASK]. \
  35.     memory_read)(offset))
  36. #define MEMORY_WRITE(index,offset,data) \
  37.     ((*cpuintf[Machine->drv->cpu[index].cpu_type & ~CPU_FLAGS_MASK]. \
  38.     memory_write)(offset,data))
  39.  
  40. void computer_writemem_byte(int cpu, int addr, int value)
  41. {
  42.     int oldcpu = cpu_getactivecpu();
  43.     memorycontextswap(cpu);
  44.     MEMORY_WRITE(cpu, addr, value);
  45.     if (oldcpu != cpu)
  46.         memorycontextswap(oldcpu);
  47. }
  48.  
  49. int computer_readmem_byte(int cpu, int addr)
  50. {
  51.     int oldcpu = cpu_getactivecpu(), result;
  52.     memorycontextswap(cpu);
  53.     result = MEMORY_READ(cpu, addr);
  54.     if (oldcpu != cpu)
  55.         memorycontextswap(oldcpu);
  56.     return result;
  57. }
  58.  
  59. /*****************************************************************************/
  60.  
  61. static void copy_to_memory (int cpu, int addr, const UINT8 *source, int num_bytes)
  62. {
  63.     int i;
  64.     for (i=0; i<num_bytes; i++)
  65.     {
  66.         computer_writemem_byte (cpu, addr+i, source[i]);
  67.     }
  68. }
  69.  
  70. static void copy_from_memory (int cpu, int addr, UINT8 *dest, int num_bytes)
  71. {
  72.     int i;
  73.     for (i=0; i<num_bytes; i++)
  74.     {
  75.         dest[i] = computer_readmem_byte (cpu, addr+i);
  76.     }
  77. }
  78.  
  79. /*****************************************************************************/
  80.  
  81. /*    hexstr2num extracts and returns the value of a hexadecimal field from the
  82.     character buffer pointed to by pString.
  83.  
  84.     When hexstr2num returns, *pString points to the character following
  85.     the first non-hexadecimal digit, or NULL if an end-of-string marker
  86.     (0x00) is encountered.
  87.  
  88. */
  89. static UINT32 hexstr2num (const char **pString)
  90. {
  91.     const char *string = *pString;
  92.     UINT32 result = 0;
  93.     if (string)
  94.     {
  95.         for(;;)
  96.         {
  97.             char c = *string++;
  98.             int digit;
  99.  
  100.             if (c>='0' && c<='9')
  101.             {
  102.                 digit = c-'0';
  103.             }
  104.             else if (c>='a' && c<='f')
  105.             {
  106.                 digit = 10+c-'a';
  107.             }
  108.             else if (c>='A' && c<='F')
  109.             {
  110.                 digit = 10+c-'A';
  111.             }
  112.             else
  113.             {
  114.                 /* not a hexadecimal digit */
  115.                 /* safety check for premature EOL */
  116.                 if (!c) string = NULL;
  117.                 break;
  118.             }
  119.             result = result*16 + digit;
  120.         }
  121.         *pString = string;
  122.     }
  123.     return result;
  124. }
  125.  
  126. /*    given a line in the hiscore.dat file, determine if it encodes a
  127.     memory range (or a game name).
  128.     For now we assume that CPU number is always a decimal digit, and
  129.     that no game name starts with a decimal digit.
  130. */
  131. static int is_mem_range (const char *pBuf)
  132. {
  133.     char c;
  134.     for(;;)
  135.     {
  136.         c = *pBuf++;
  137.         if (c == 0) return 0; /* premature EOL */
  138.         if (c == ':') break;
  139.     }
  140.     c = *pBuf; /* character following first ':' */
  141.  
  142.     return    (c>='0' && c<='9') ||
  143.             (c>='a' && c<='f') ||
  144.             (c>='A' && c<='F');
  145. }
  146.  
  147. /*    matching_game_name is used to skip over lines until we find <gamename>: */
  148. static int matching_game_name (const char *pBuf, const char *name)
  149. {
  150.     while (*name)
  151.     {
  152.         if (*name++ != *pBuf++) return 0;
  153.     }
  154.     return (*pBuf == ':');
  155. }
  156.  
  157. /*****************************************************************************/
  158.  
  159. /* safe_to_load checks the start and end values of each memory range */
  160. static int safe_to_load (void)
  161. {
  162.     struct mem_range *mem_range = state.mem_range;
  163.     while (mem_range)
  164.     {
  165.         if (computer_readmem_byte (mem_range->cpu, mem_range->addr) !=
  166.             mem_range->start_value)
  167.         {
  168.             return 0;
  169.         }
  170.         if (computer_readmem_byte (mem_range->cpu, mem_range->addr + mem_range->num_bytes - 1) !=
  171.             mem_range->end_value)
  172.         {
  173.             return 0;
  174.         }
  175.         mem_range = mem_range->next;
  176.     }
  177.     return 1;
  178. }
  179.  
  180. /* hs_free disposes of the mem_range linked list */
  181. static void hs_free (void)
  182. {
  183.     struct mem_range *mem_range = state.mem_range;
  184.     while (mem_range)
  185.     {
  186.         struct mem_range *next = mem_range->next;
  187.         free (mem_range);
  188.         mem_range = next;
  189.     }
  190.     state.mem_range = NULL;
  191. }
  192.  
  193. static void hs_load (void)
  194. {
  195.     void *f = osd_fopen (Machine->gamedrv->name, 0, OSD_FILETYPE_HIGHSCORE, 0);
  196.     state.hiscores_have_been_loaded = 1;
  197.     LOG(("hs_load\n"));
  198.     if (f)
  199.     {
  200.         struct mem_range *mem_range = state.mem_range;
  201.         LOG(("loading...\n"));
  202.         while (mem_range)
  203.         {
  204.             UINT8 *data = malloc (mem_range->num_bytes);
  205.             if (data)
  206.             {
  207.                 /*    this buffer will almost certainly be small
  208.                     enough to be dynamically allocated, but let's
  209.                     avoid memory trashing just in case
  210.                 */
  211.                 osd_fread (f, data, mem_range->num_bytes);
  212.                 copy_to_memory (mem_range->cpu, mem_range->addr, data, mem_range->num_bytes);
  213.                 free (data);
  214.             }
  215.             mem_range = mem_range->next;
  216.         }
  217.         osd_fclose (f);
  218.     }
  219. }
  220.  
  221. static void hs_save (void)
  222. {
  223.     void *f = osd_fopen (Machine->gamedrv->name, 0, OSD_FILETYPE_HIGHSCORE, 1);
  224.     LOG(("hs_save\n"));
  225.     if (f)
  226.     {
  227.         struct mem_range *mem_range = state.mem_range;
  228.         LOG(("saving...\n"));
  229.         while (mem_range)
  230.         {
  231.             UINT8 *data = malloc (mem_range->num_bytes);
  232.             if (data)
  233.             {
  234.                 /*    this buffer will almost certainly be small
  235.                     enough to be dynamically allocated, but let's
  236.                     avoid memory trashing just in case
  237.                 */
  238.                 copy_from_memory (mem_range->cpu, mem_range->addr, data, mem_range->num_bytes);
  239.                 osd_fwrite(f, data, mem_range->num_bytes);
  240.             }
  241.             mem_range = mem_range->next;
  242.         }
  243.         osd_fclose(f);
  244.     }
  245. }
  246.  
  247. /*****************************************************************************/
  248. /* public API */
  249.  
  250. /* call hs_open once after loading a game */
  251. void hs_open (const char *name)
  252. {
  253.     void *f = osd_fopen (NULL, db_filename, OSD_FILETYPE_HIGHSCORE_DB, 0);
  254.     state.mem_range = NULL;
  255.  
  256.     LOG(("hs_open: '%s'\n", name));
  257.  
  258.     if (f)
  259.     {
  260.         char buffer[MAX_CONFIG_LINE_SIZE];
  261.         enum { FIND_NAME, FIND_DATA, FETCH_DATA } mode;
  262.         mode = FIND_NAME;
  263.  
  264.         while (osd_fgets (buffer, MAX_CONFIG_LINE_SIZE, f))
  265.         {
  266.             if (mode==FIND_NAME)
  267.             {
  268.                 if (matching_game_name (buffer, name))
  269.                 {
  270.                     mode = FIND_DATA;
  271.                     LOG(("hs config found!\n"));
  272.                 }
  273.             }
  274.             else if (is_mem_range (buffer))
  275.             {
  276.                 const char *pBuf = buffer;
  277.                 struct mem_range *mem_range = malloc(sizeof(struct mem_range));
  278.                 if (mem_range)
  279.                 {
  280.                     mem_range->cpu = hexstr2num (&pBuf);
  281.                     mem_range->addr = hexstr2num (&pBuf);
  282.                     mem_range->num_bytes = hexstr2num (&pBuf);
  283.                     mem_range->start_value = hexstr2num (&pBuf);
  284.                     mem_range->end_value = hexstr2num (&pBuf);
  285.  
  286.                     mem_range->next = NULL;
  287.                     {
  288.                         struct mem_range *last = state.mem_range;
  289.                         while (last && last->next) last = last->next;
  290.                         if (last == NULL)
  291.                         {
  292.                             state.mem_range = mem_range;
  293.                         }
  294.                         else
  295.                         {
  296.                             last->next = mem_range;
  297.                         }
  298.                     }
  299.  
  300.                     mode = FETCH_DATA;
  301.                 }
  302.                 else
  303.                 {
  304.                     hs_free();
  305.                     break;
  306.                 }
  307.             }
  308.             else
  309.             {
  310.                 /* line is a game name */
  311.                 if (mode == FETCH_DATA) break;
  312.             }
  313.         }
  314.         osd_fclose (f);
  315.     }
  316. }
  317.  
  318. /* call hs_init when emulation starts, and when the game is reset */
  319. void hs_init (void)
  320. {
  321.     struct mem_range *mem_range = state.mem_range;
  322.     state.hiscores_have_been_loaded = 0;
  323.  
  324.     while (mem_range)
  325.     {
  326.         computer_writemem_byte(
  327.             mem_range->cpu,
  328.             mem_range->addr,
  329.             ~mem_range->start_value
  330.         );
  331.  
  332.         computer_writemem_byte(
  333.             mem_range->cpu,
  334.             mem_range->addr + mem_range->num_bytes-1,
  335.             ~mem_range->end_value
  336.         );
  337.         mem_range = mem_range->next;
  338.     }
  339. }
  340.  
  341. /* call hs_update periodically (i.e. once per frame) */
  342. void hs_update (void)
  343. {
  344.     if (state.mem_range)
  345.     {
  346.         if (!state.hiscores_have_been_loaded)
  347.         {
  348.             if (safe_to_load()) hs_load();
  349.         }
  350.     }
  351. }
  352.  
  353. /* call hs_close when done playing game */
  354. void hs_close (void)
  355. {
  356.     if (state.hiscores_have_been_loaded) hs_save();
  357.     hs_free();
  358. }
  359.